
#ifndef __VEDA_JSON_H__
#define __VEDA_JSON_H__

#include "VIO/VJson.h"

namespace Veda{

class StaticString
{
public:
	explicit StaticString( const char* czstring ) : str_( czstring ){}
	operator const char* () const{return str_;}
	const char* c_str() const{return str_;}
	
private:
	const char* str_;
};


class ValueAllocator
{
	enum { unknown = (unsigned)-1 };
public:
	char* makeMemberName( const char* memberName )
	{
		return duplicateStringValue( memberName );
	}
	void releaseMemberName( char* memberName )
	{
		releaseStringValue( memberName );
	}
	char* duplicateStringValue( const char* value, uint length = unknown )
	{
		if ( length == unknown )
			length = (uint)strlen(value);
		char* newString = static_cast<char* >( malloc( length + 1 ) );
		memcpy( newString, value, length );
		newString[length] = 0;
		return newString;
	}
	void releaseStringValue( char* value )
	{
		if ( value )
			free( value );	
	}
};
static ValueAllocator *&valueAllocator()
{
	static ValueAllocator defaultAllocator;
	static ValueAllocator *valueAllocator = &defaultAllocator;
	return valueAllocator;
}


class CZString 
{
public:
	enum DuplicationPolicy 
	{
		noDuplication = 0,
		duplicate,
		duplicateOnCopy
	};
	CZString( int index ) : cstr_( 0 ), index_( index ){}
	CZString( const char* cstr, DuplicationPolicy allocate )
		: cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr )
		, index_( allocate ){}
	CZString( const CZString &other )
		: cstr_( other.index_ != noDuplication &&  other.cstr_ != 0 ? valueAllocator()->makeMemberName( other.cstr_ ) : other.cstr_ )
		, index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_ ){}
	~CZString()
	{
		if ( cstr_  &&  index_ == duplicate )
			valueAllocator()->releaseMemberName( const_cast<char*>( cstr_ ) );
	}

	void swap( CZString &other )
	{
		std::swap( cstr_, other.cstr_ );
		std::swap( index_, other.index_ );
	}
	CZString &operator =( const CZString &other )
	{
		CZString temp( other );
		swap( temp );
		return *this;
	}
	bool operator<( const CZString &other ) const
	{
		if ( cstr_ )
			return strcmp( cstr_, other.cstr_ ) < 0;
		return index_ < other.index_;
	}
	bool operator==( const CZString &other ) const
	{
		if ( cstr_ )
			return strcmp( cstr_, other.cstr_ ) == 0;
		return index_ == other.index_;
	}
	int index() const{return index_;}
	const char* c_str() const{return cstr_;}
	bool isStaticString() const{return index_ == noDuplication;}
private:
	const char* cstr_;
	int index_;
};


class ValueIteratorBase
{
public:
	ValueIteratorBase() : current_(), isNull_( true ){}
	explicit ValueIteratorBase( const VJson::ObjectValues::iterator &current ) : current_( current ), isNull_( false ){}

	ValueIteratorBase& operator =( const ValueIteratorBase& other )
	{
		current_ = other.current_;
		isNull_ = other.isNull_;
		return *this;
	}
	bool operator ==( const ValueIteratorBase& other ) const
	{
		if ( isNull_ )
			return other.isNull_;
		return current_ == other.current_;
	}
	bool operator !=( const ValueIteratorBase& other ) const
	{
		return !(*this == other);
	}
	int operator -( const ValueIteratorBase& other ) const
	{
		if ( isNull_  &&  other.isNull_ )
			return 0;
		int myDistance = 0;
		for ( VJson::ObjectValues::iterator it = current_; it != other.current_; ++it )
			++myDistance;
		return myDistance;
	}
	ValueIteratorBase operator++( int )
	{
		ValueIteratorBase temp( *this );
		++*this;
		return temp;
	}
	ValueIteratorBase operator--( int )
	{
		ValueIteratorBase temp( *this );
		--*this;
		return temp;
	}
	ValueIteratorBase& operator--()
	{
		--current_;
		return *this;
	}
	ValueIteratorBase& operator++()
	{
		++current_;
		return *this;
	}
	VJson& operator *() const
	{
		return current_->second;
	}
	
	/// Return either the index or the member name of the referenced value as a VJson.
	VJson key() const
	{
		const CZString czstring = (*current_).first;
		if ( czstring.c_str() )
		{
			if ( czstring.isStaticString() )
				return VJson( StaticString( czstring.c_str() ) );
			return VJson( czstring.c_str() );
		}
		return VJson( czstring.index() );
	}

	/// Return the index of the referenced VJson. -1 if it is not an arrayValue.
	uint index() const
	{
		const CZString czstring = (*current_).first;
		if ( !czstring.c_str() )
			return czstring.index();
		return uint( -1 );
	}

	/// Return the member name of the referenced VJson. "" if it is not an objectValue.
	const char* memberName() const
	{
		const char *name = (*current_).first.c_str();
		return name ? name : "";
	}

protected:
	VJson::ObjectValues::iterator current_;
	// Indicates that iterator is for a null value.
	bool isNull_;
};

class ValueConstIterator : public ValueIteratorBase
{
	friend class VJson;
public:
	ValueConstIterator(){}
private:
	explicit ValueConstIterator( const VJson::ObjectValues::iterator& current ) : ValueIteratorBase(current){}
};

class ValueIterator : public ValueIteratorBase
{
	friend class VJson;
public:
	ValueIterator(){}
	ValueIterator( const ValueConstIterator& other ) : ValueIteratorBase( other ){}
	ValueIterator( const ValueIterator& other ) : ValueIteratorBase( other ){}
private:
	explicit ValueIterator( const VJson::ObjectValues::iterator& current ) : ValueIteratorBase(current){}
};


}

#endif

